﻿
using System;
using System.Collections.Generic;
using System.Windows.Media.Media3D;

namespace LxCFD
{
    public class FluentMeshBase
    {
        public Point3D[] FlNodes { get; set; }
        public List<FlZone> FlZones { get; set; } = new List<FlZone>();
        public List<FlThread> FlThreads { get; set; } = new List<FlThread>();
        protected bool ConvertToMesh()
        {
            FvMesh mesh = new FvMesh();
            RemarkID();
            DistributeThreadsToFlZone(mesh);
            foreach (FlZone fzone in this.FlZones)
            {
                fzone.AddToFvZone(mesh);
            }
            DistributeNodesToFvZone(mesh);
            AppRes.FvMesh = mesh;
            return true;
        }
        protected void RemarkID()
        {
            for (int i1 = 0; i1 < FlZones.Count; i1++)
            {
                FlZones[i1].ID = i1;
            }
            for (int i1 = 0; i1 < FlThreads.Count; i1++)
            {
                FlThreads[i1].ID = i1;
            }
        }
        protected int FindZoneByCell(int cellID)
        {
            foreach (FlZone z in this.FlZones)
            {
                if (cellID >= z.Index.Start && cellID <= z.Index.End)
                {
                    return z.ID;
                }
            }
            return -1;
        }
        protected void DistributeThreadsToFlZone(FvMesh mesh)
        {
            foreach (FlThread fthread in this.FlThreads)
            {
                int oZone = FindZoneByCell(fthread.Faces[0].c0);
                int c1Flag = fthread.Faces[0].c1;
                if (c1Flag < 0)
                {
                    FlZones[oZone].AddThread(fthread, FThreadTypes.boundary);
                    //FlZones[oZone].Threads.Add(fthread);
                    //FlZones[oZone].ThreadsType.Add(FThreadTypes.boundary);
                }
                else
                {
                    int nZone = FindZoneByCell(c1Flag);
                    if (nZone == oZone)
                    {
                        FlZones[oZone].AddThread(fthread, FThreadTypes.interior);
                        //FlZones[oZone].Threads.Add(fthread);
                        //FlZones[oZone].ThreadsType.Add(FThreadTypes.interior);
                    }
                    else
                    {
                        FlZones[oZone].AddThread(fthread, FThreadTypes.interface_c0);
                        FlZones[nZone].AddThread(fthread, FThreadTypes.interface_c1);
                        //FlZones[oZone].Threads.Add(fthread);
                        //FlZones[oZone].ThreadsType.Add(FThreadTypes.interface_c0);
                        //FlZones[nZone].Threads.Add(fthread);
                        //FlZones[nZone].ThreadsType.Add(FThreadTypes.interface_c1);
                        FvContact contact = new FvContact() { name = fthread.name, IsConode = true };
                        fthread.RootContact = contact;
                        mesh.Contacts.Add(contact);
                    }
                }
            }
        }

        protected void DistributeNodesToFvZone(FvMesh mesh)
        {
            int[] nodeNewIndex = new int[this.FlNodes.Length];
            foreach (FvZone z in mesh.Zones)
            {
                for (int i1 = 0; i1 < nodeNewIndex.Length; i1++)
                {
                    nodeNewIndex[i1] = -1;
                }
                Point3DCollection ps = new Point3DCollection();
                foreach (FvFace f in z.Faces)
                {
                    for (int i3 = 0; i3 < f.NodeIDs.Length; i3++)
                    {
                        int oldIndex = f.NodeIDs[i3];
                        if (nodeNewIndex[oldIndex] < 0)
                        {
                            nodeNewIndex[oldIndex] = ps.Count;
                            f.NodeIDs[i3] = ps.Count;
                            ps.Add(this.FlNodes[oldIndex]);
                        }
                        else
                        {
                            f.NodeIDs[i3] = nodeNewIndex[oldIndex];
                        }
                    }
                }
                z.Nodes = ps;
            }
        }
        #region 嵌套类
        public struct Face
        {
            public Face(string[] ss)
            {
                Nodes = new int[ss.Length - 2];
                int i2 = 0;
                for (; i2 < Nodes.Length; i2++)
                {
                    Nodes[i2] = Convert.ToInt32(ss[i2], 16) - 1;
                }
                c0 = Convert.ToInt32(ss[i2], 16) - 1;
                c1 = Convert.ToInt32(ss[i2 + 1], 16) - 1;
            }
            public int[] Nodes { get; set; }
            public int c0 { get; set; }//对应cell的编号
            public int c1 { get; set; }
        }

        public class FlHead : HeadBase
        {
            public IndexRecorder Index;
            public void SetHead(string[] ss)
            {
                ID = Convert.ToInt32(ss[1], 16);
                Index.Start = Convert.ToInt32(ss[2], 16) - 1;
                Index.End = Convert.ToInt32(ss[3], 16) - 1;
            }
        }
        public class FlThread : FlHead
        {
            public Face[] Faces { get; set; }
            public FvContact RootContact { get; set; }
        }
        public class FlZone : FlHead
        {
            public List<FlThread> Threads { get; set; } = new List<FlThread>();//临时变量
            public List<FThreadTypes> ThreadsType { get; set; } = new List<FThreadTypes>();//对应于zoneThreads 

            public void AddThread(FlThread flThread,FThreadTypes fThreadType)
            {
                Threads.Add(flThread);
                ThreadsType.Add(fThreadType);
            }
            public void AddToFvZone(FvMesh mesh)
            {
                FvZone mzone = new FvZone()
                {
                    name = name,
                    ID = ID,
                };
                int faceflag = 0;
                foreach (FlThread ft in Threads)
                {
                    faceflag += ft.Faces.Length;
                }
                mzone.Faces = new FvFace[faceflag];
                int first_index = Index.Start;
                faceflag = 0;
                //先查找添加interior
                for (int i2 = 0; i2 < Threads.Count; i2++)
                {
                    if (ThreadsType[i2] == FThreadTypes.interior)
                    {
                        foreach (Face ff in Threads[i2].Faces)
                        {
                            mzone.Faces[faceflag] = new FvFace(ff.Nodes, ff.c0 - first_index, ff.c1 - first_index, false);
                            faceflag++;
                        }
                    }
                }
                mzone.InnerIndex = new IndexNumber(0, Index.GetCount() - 1, 0, faceflag - 1);
                int deltacellfacecount = mzone.InnerIndex.CellIDs.End - mzone.InnerIndex.FaceIDs.End;// EndFaceIndex;
                //后查找添加interior之外的
                for (int i2 = 0; i2 < Threads.Count; i2++)
                {
                    if (ThreadsType[i2] == FThreadTypes.interior) continue;
                    FvThread mthread = new FvThread(mzone)
                    {
                        name = Threads[i2].name,
                        ID = Threads[i2].ID,
                    };
                    int startFaceID = faceflag;
                    //把thread中的face全部添加到mesh zone中的faces
                    switch (ThreadsType[i2])
                    {
                        case FThreadTypes.boundary:
                            foreach (Face ff in Threads[i2].Faces)
                            {
                                mzone.Faces[faceflag] = new FvFace(ff.Nodes, ff.c0 - first_index, faceflag + deltacellfacecount, false);
                                faceflag++;
                            }
                            break;
                        case FThreadTypes.interface_c0:
                            foreach (Face ff in Threads[i2].Faces)
                            {
                                mzone.Faces[faceflag] = new FvFace(ff.Nodes, ff.c0 - first_index, faceflag + deltacellfacecount, false);
                                faceflag++;
                            }
                            mthread.RootContact = Threads[i2].RootContact;
                            mthread.RootContact.OZone = mzone;
                            mthread.RootContact.OThread = mthread;
                            break;
                        case FThreadTypes.interface_c1:
                            foreach (Face ff in Threads[i2].Faces)
                            {
                                mzone.Faces[faceflag] = new FvFace(ff.Nodes, ff.c1 - first_index, faceflag + deltacellfacecount, true);
                                faceflag++;
                            }
                            mthread.RootContact = Threads[i2].RootContact;
                            mthread.RootContact.NZone = mzone;
                            mthread.RootContact.NThread = mthread;
                            break;
                        default:
                            break;
                    }
                    int endFaceID = faceflag - 1;
                    mthread.ThreadIndex = new IndexNumber(startFaceID + deltacellfacecount, endFaceID + deltacellfacecount, startFaceID, endFaceID);
                    mzone.BoundThreads.Add(mthread);
                }
                int totalEndFaceID = faceflag - 1;
                mzone.TotalIndex = new IndexNumber(0, totalEndFaceID + deltacellfacecount, 0, totalEndFaceID);
                mesh.Zones.Add(mzone);
            }
        }
        public enum FThreadTypes
        {
            interior, boundary, interface_c0, interface_c1,
        }
        #endregion
    }
}
